package filesystem.service;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import filesystem.GlobalFSData;
import filesystem.model.Disk;
import filesystem.model.FAT;
import filesystem.model.File;

public class DiskService {

	// save directory or file into the disk
	public static void saveFile(File file, Disk disk) {
		disk.getDiskTable().set(file.getStartIndex(), file);
	}

	// archieve content from disk by index
	public static Object getDiskContent(int index, Disk disk) {
		return disk.getDiskTable().get(index);
	}

	// save content into the disk
	// content's type is object, it can be file model or string or others
	public static void saveContent(Object content, Disk disk, int index) {
		FATService.SetBlockValue(-1, GlobalFSData.getFat(), index);
		disk.getDiskTable().set(index, content);
	}

	// apply free block, return the vacant index of disk, -1 stand for disk full
	public static int applyFreeBlock(FAT fat) {
		for (int i = 3; i < fat.getTable().length; i++) {
			if (fat.getTable()[i] == 0) {
				return i;
			}
		}
		return -1;
	}
	public static int applyFreeBlock(Disk disk) {
		for(int i = 3;i < disk.getDiskTable().size();i++) {
			if(disk.getDiskTable().get(i) == null) {
				return i;
			}
		}
		return -1;
	}
	// delete object from disk
	public static void deleteObject(Disk disk, int index) {
		FATService.freeBlock(index, GlobalFSData.getFat());
		disk.getDiskTable().set(index, null);
	}

	// check if the disk is valid
	public static Disk checkDisk(Disk disk) {
		if (disk == null) {
			return new Disk();
		}
		return disk;
	}

	// get the free blocks counts
	public static int getDiskFreeCnt() {
		return GlobalFSData.getFat().getFreeCount();
	}

	public static HashMap<String, Object> getDirsAndFiles(Disk disk) {
		HashMap<String, Object> hashmap = new HashMap<String, Object>();
		List<Object> files = new ArrayList<>();
		List<Object> dirs = new ArrayList<>();
		List<Object> allFiles = new ArrayList<>();
		List<Object> contents = disk.getDiskTable();
		List<File> exeFiles = new ArrayList<>();

		for (int i = 0; i < Disk.BLOCK_SIZE; i++) {
			if (contents.get(i) instanceof File) {
				File file = (File) contents.get(i);
				allFiles.add(file);
				if (file.getAttribute() == File.DIRECTORY || file.getAttribute() == File.ROOT) {
					dirs.add(file);
					List<File> subFiles = file.getSubFiles();
					for (Object f : subFiles) {
						if (((File) f).getAttribute() == File.FILE) {
							if (((File) f).getType() == File.EXE) {
								exeFiles.add((File) f);
							} else if (((File) f).getType() == File.NORMAL) {
							}
							allFiles.add(f);
						}

					}
				}
			}
		}

		hashmap.put("files", files);
		hashmap.put("dirs", dirs);
		hashmap.put("allFiles", allFiles);
		hashmap.put("exeFiles", exeFiles);
		return hashmap;
	}

	public static int calculateNeedBlock(String Data) {
		if (Data != null) {
			double requireBlock = Data.length() * 1.0 / 64;
			return (int) Math.ceil(requireBlock);
		} else {
			return 0;
		}
	}

	// save the virtual disk to the real disk
	public static void save2Disk(Disk disk, String filename, FAT fat) {
		java.io.File file = new java.io.File(filename);
		disk.setFat(fat);
		try {
			FileOutputStream output = new FileOutputStream(file);
			ObjectOutputStream oos = new ObjectOutputStream(output);
			oos.writeObject(disk);
			oos.flush();
			oos.close();
			output.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// achieve the disk data from the real disk
	public static Object achieve2Disk(String filename) {
		java.io.File file = new java.io.File(filename);
		try {
			FileInputStream input = new FileInputStream(file);
			ObjectInputStream ois = new ObjectInputStream(input);

			//利用IO流，从二进制文件中读取实例对象
			Object object = ois.readObject();
			ois.close();
			input.close();
			return object;
		} catch (java.io.FileNotFoundException e) {
			// do nothing
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
